home *** CD-ROM | disk | FTP | other *** search
/ Aminet 45 / Aminet 45 (2001)(GTI - Schatztruhe)[!][Oct 2001].iso / Aminet / gfx / x11 / x3270_3_2_16.lha / amiga_src / popups.c < prev    next >
C/C++ Source or Header  |  2009-02-26  |  15KB  |  653 lines

  1. /*
  2.  * Copyright 1993, 1994, 1995, 1999, 2000 by Paul Mattes.
  3.  *  Permission to use, copy, modify, and distribute this software and its
  4.  *  documentation for any purpose and without fee is hereby granted,
  5.  *  provided that the above copyright notice appear in all copies and that
  6.  *  both that copyright notice and this permission notice appear in
  7.  *  supporting documentation.
  8.  */
  9.  
  10. /*
  11.  *    popups.c
  12.  *        This module handles pop-up dialogs: errors, host names,
  13.  *        font names, information.
  14.  */
  15.  
  16. #include "globals.h"
  17. #include <X11/Shell.h>
  18. #include <X11/StringDefs.h>
  19. #include <X11/Xaw/Command.h>
  20. #include <X11/Xaw/Dialog.h>
  21. #include <X11/Xaw/Form.h>
  22. #include <X11/Xaw/Label.h>
  23. #include <X11/Xaw/Text.h>
  24. #include <stdarg.h>
  25. #include "objects.h"
  26. #include "appres.h"
  27.  
  28. #include "actionsc.h"
  29. #include "macrosc.h"
  30. #include "popupsc.h"
  31. #include "screenc.h"
  32. #include "utilc.h"
  33. #include "xioc.h"
  34.  
  35. static char vmsgbuf[4096];
  36.  
  37. static enum form_type forms[] = { FORM_NO_WHITE, FORM_NO_CC, FORM_AS_IS };
  38.  
  39.  
  40. /*
  41.  * General popup support
  42.  */
  43.  
  44. /* Find the parent of a window */
  45. static Window
  46. parent_of(Window w)
  47. {
  48.     Window root, parent, *wchildren;
  49.     unsigned int nchildren;
  50.  
  51.     XQueryTree(display, w, &root, &parent, &wchildren, &nchildren);
  52.     XFree((char *)wchildren);
  53.     return parent;
  54. }
  55.  
  56. /*
  57.  * Find the base window (the one with the wmgr decorations) and the virtual
  58.  * root, so we can pop up a window relative to them.
  59.  */
  60. void
  61. toplevel_geometry(Position *x, Position *y, Dimension *width,
  62.     Dimension *height)
  63. {
  64.     Window tlw = XtWindow(toplevel);
  65.     Window win;
  66.     Window parent;
  67.     int nw;
  68.     struct {
  69.         Window w;
  70.         XWindowAttributes wa;
  71.     } ancestor[10];
  72.     XWindowAttributes wa, *base_wa, *root_wa;
  73.  
  74.     /*
  75.      * Trace the family tree of toplevel.
  76.      */
  77.     for (win = tlw, nw = 0; ; win = parent) {
  78.         parent = parent_of(win);
  79.         ancestor[nw].w = parent;
  80.         XGetWindowAttributes(display, parent, &ancestor[nw].wa);
  81.         ++nw;
  82.         if (parent == root_window)
  83.             break;
  84.     }
  85.  
  86.     /*
  87.      * Figure out if they're running a virtual desktop, by seeing if
  88.      * the 1st child of root is bigger than it is.  If so, pretend that
  89.      * the virtual desktop is the root.
  90.      */
  91.     if (nw > 1 &&
  92.         (ancestor[nw-2].wa.width > ancestor[nw-1].wa.width ||
  93.          ancestor[nw-2].wa.height > ancestor[nw-1].wa.height))
  94.         --nw;
  95.     root_wa = &ancestor[nw-1].wa;
  96.  
  97.     /*
  98.      * Now identify the base window as the window below the root
  99.      * window.
  100.      */
  101.     if (nw >= 2) {
  102.         base_wa = &ancestor[nw-2].wa;
  103.     } else {
  104.         XGetWindowAttributes(display, tlw, &wa);
  105.         base_wa = &wa;
  106.     }
  107.  
  108.     *x = base_wa->x + root_wa->x;
  109.     *y = base_wa->y + root_wa->y;
  110.     *width = base_wa->width + 2*base_wa->border_width;
  111.     *height = base_wa->height + 2*base_wa->border_width;
  112. }
  113.  
  114. /* Pop up a popup shell */
  115. void
  116. popup_popup(Widget shell, XtGrabKind grab)
  117. {
  118.     XtPopup(shell, grab);
  119.     XSetWMProtocols(display, XtWindow(shell), &a_delete_me, 1);
  120. }
  121.  
  122. static enum placement CenterD = Center;
  123. enum placement *CenterP = &CenterD;
  124. static enum placement BottomD = Bottom;
  125. enum placement *BottomP = &BottomD;
  126. static enum placement LeftD = Left;
  127. enum placement *LeftP = &LeftD;
  128. static enum placement RightD = Right;
  129. enum placement *RightP = &RightD;
  130.  
  131. /* Place a popped-up shell */
  132. void
  133. place_popup(Widget w, XtPointer client_data, XtPointer call_data unused)
  134. {
  135.     Dimension width, height;
  136.     Position x = 0, y = 0;
  137.     Dimension win_width, win_height;
  138.     Dimension popup_width, popup_height;
  139.     enum placement p = *(enum placement *)client_data;
  140.  
  141.     /* Get and fix the popup's dimensions */
  142.     XtRealizeWidget(w);
  143.     XtVaGetValues(w,
  144.         XtNwidth, &width,
  145.         XtNheight, &height,
  146.         NULL);
  147.     XtVaSetValues(w,
  148.         XtNheight, height,
  149.         XtNwidth, width,
  150.         XtNbaseHeight, height,
  151.         XtNbaseWidth, width,
  152.         XtNminHeight, height,
  153.         XtNminWidth, width,
  154.         XtNmaxHeight, height,
  155.         XtNmaxWidth, width,
  156.         NULL);
  157.  
  158.     /*
  159.      * Find the geometry of the parent of the toplevel window in order to
  160.      * place the popup window.  This is done with an Xlib call (asking the
  161.      * server explicitly) rather than the Xt call.  Why?  At startup,
  162.      * Xt may not yet know the parent window has been moved by the window
  163.      * manager.
  164.      */
  165.     toplevel_geometry(&x, &y, &win_width, &win_height);
  166.  
  167.     switch (p) {
  168.         case Center:
  169.         XtVaGetValues(w,
  170.             XtNwidth, &popup_width,
  171.             XtNheight, &popup_height,
  172.             NULL);
  173.         XtVaSetValues(w,
  174.             XtNx, x + (win_width-popup_width) / (unsigned) 2,
  175.             XtNy, y + (win_height-popup_height) / (unsigned) 2,
  176.             NULL);
  177.         break;
  178.         case Bottom:
  179.         XtVaSetValues(w,
  180.             XtNx, x,
  181.             XtNy, y + win_height + 2,
  182.             NULL);
  183.         break;
  184.         case Left:
  185.         XtVaGetValues(w,
  186.             XtNwidth, &popup_width,
  187.             NULL);
  188.         XtVaSetValues(w,
  189.             XtNx, x - popup_width - (win_width - main_width) - 2,
  190.             XtNy, y,
  191.             NULL);
  192.         break;
  193.         case Right:
  194.         XtVaSetValues(w,
  195.             XtNx, x + win_width + 2,
  196.             XtNy, y,
  197.             NULL);
  198.         break;
  199.     }
  200. }
  201.  
  202. /* Action called when "Return" is pressed in data entry popup */
  203. void
  204. PA_confirm_action(Widget w, XEvent *event, String *params, Cardinal *num_params)
  205. {
  206.     Widget w2;
  207.  
  208.     /* Find the Confirm or Okay button */
  209.     w2 = XtNameToWidget(XtParent(w), ObjConfirmButton);
  210.     if (w2 == NULL)
  211.         w2 = XtNameToWidget(XtParent(w), ObjConfirmButton);
  212.     if (w2 == NULL)
  213.         w2 = XtNameToWidget(w, ObjConfirmButton);
  214.     if (w2 == NULL) {
  215.         xs_warning("confirm: cannot find %s", ObjConfirmButton);
  216.         return;
  217.     }
  218.  
  219.     /* Call its "notify" event */
  220.     XtCallActionProc(w2, "set", event, params, *num_params);
  221.     XtCallActionProc(w2, "notify", event, params, *num_params);
  222.     XtCallActionProc(w2, "unset", event, params, *num_params);
  223. }
  224.  
  225. /* Callback for "Cancel" button in data entry popup */
  226. static void
  227. cancel_button_callback(Widget w unused, XtPointer client_data,
  228.     XtPointer call_data unused)
  229. {
  230.     XtPopdown((Widget) client_data);
  231. }
  232.  
  233. /*
  234.  * Callback for text source changes.  Ensures that the dialog text does not
  235.  * contain white space -- especially newlines.
  236.  */
  237. static void
  238. popup_dialog_callback(Widget w, XtPointer client_data,
  239.     XtPointer call_data unused)
  240. {
  241.     static Boolean called_back = False;
  242.     XawTextBlock b, nullb;    /* firstPos, length, ptr, format */
  243.     XawTextPosition pos = 0;
  244.     int front_len = 0;
  245.     int end_len = 0;
  246.     int end_pos = 0;
  247.     int i;
  248.     enum { FRONT, MIDDLE, END } place = FRONT;
  249.     enum form_type *ftp = (enum form_type *)client_data;
  250.  
  251.     if (*ftp == FORM_AS_IS)
  252.         return;
  253.  
  254.     if (called_back)
  255.         return;
  256.     else
  257.         called_back = True;
  258.  
  259.     nullb.firstPos = 0;
  260.     nullb.length = 0;
  261.     nullb.ptr = NULL;
  262.  
  263.     /*
  264.      * Scan the text for whitespace.  Leading whitespace is deleted;
  265.      * embedded whitespace causes the rest of the text to be deleted.
  266.      */
  267.     while (1) {
  268.         XawTextSourceRead(w, pos, &b, 1024);
  269.         if (b.length <= 0)
  270.             break;
  271.         nullb.format = b.format;
  272.         if (place == END) {
  273.             end_len += b.length;
  274.             continue;
  275.         }
  276.         for (i = 0; i < b.length; i++) {
  277.             char c;
  278.  
  279.             c = *(b.ptr + i);
  280.             if (isspace(c) && (*ftp != FORM_NO_CC || c != ' ')) {
  281.                 if (place == FRONT) {
  282.                     front_len++;
  283.                     continue;
  284.                 } else {
  285.                     end_pos = b.firstPos + i;
  286.                     end_len = b.length - i;
  287.                     place = END;
  288.                     break;
  289.                 }
  290.             } else
  291.                 place = MIDDLE;
  292.         }
  293.         pos += b.length;
  294.         if (b.length < 1024)
  295.             break;
  296.     }
  297.     if (front_len)
  298.         XawTextSourceReplace(w, 0, front_len, &nullb);
  299.     if (end_len)
  300.         XawTextSourceReplace(w, end_pos - front_len,
  301.             end_pos - front_len + end_len, &nullb);
  302.     called_back = False;
  303. }
  304.  
  305. /* Create a simple data entry popup */
  306. Widget
  307. create_form_popup(const char *name, XtCallbackProc callback,
  308.     XtCallbackProc callback2, enum form_type form_type)
  309. {
  310.     char *widgetname;
  311.     Widget shell;
  312.     Widget dialog;
  313.     Widget w;
  314.  
  315.     /* Create the popup shell */
  316.  
  317.     widgetname = xs_buffer("%sPopup", name);
  318.     if (isupper(widgetname[0]))
  319.         widgetname[0] = tolower(widgetname[0]);
  320.     shell = XtVaCreatePopupShell(
  321.         widgetname, transientShellWidgetClass, toplevel,
  322.         NULL);
  323.     XtFree(widgetname);
  324.     XtAddCallback(shell, XtNpopupCallback, place_popup, (XtPointer)CenterP);
  325.  
  326.     /* Create a dialog in the popup */
  327.  
  328.     dialog = XtVaCreateManagedWidget(
  329.         ObjDialog, dialogWidgetClass, shell,
  330.         XtNvalue, "",
  331.         NULL);
  332.     XtVaSetValues(XtNameToWidget(dialog, XtNlabel),
  333.         NULL);
  334.  
  335.     /* Add "Confirm" and "Cancel" buttons to the dialog */
  336.     w = XtVaCreateManagedWidget(
  337.         ObjConfirmButton, commandWidgetClass, dialog,
  338.         NULL);
  339.     XtAddCallback(w, XtNcallback, callback, (XtPointer)dialog);
  340.     if (callback2) {
  341.         w = XtVaCreateManagedWidget(
  342.             ObjConfirm2Button, commandWidgetClass, dialog,
  343.             NULL);
  344.         XtAddCallback(w, XtNcallback, callback2, (XtPointer)dialog);
  345.     }
  346.     w = XtVaCreateManagedWidget(
  347.         ObjCancelButton, commandWidgetClass, dialog,
  348.         NULL);
  349.     XtAddCallback(w, XtNcallback, cancel_button_callback, (XtPointer) shell);
  350.  
  351.     if (form_type == FORM_AS_IS)
  352.         return shell;
  353.  
  354.     /* Modify the translations for the objects in the dialog */
  355.  
  356.     w = XtNameToWidget(dialog, XtNvalue);
  357.     if (w == NULL)
  358.         xs_warning("Cannot find \"%s\" in dialog", XtNvalue);
  359.  
  360.     /* Set a callback for text modifications */
  361.     w = XawTextGetSource(w);
  362.     if (w == NULL)
  363.         XtWarning("Cannot find text source in dialog");
  364.     else
  365.         XtAddCallback(w, XtNcallback, popup_dialog_callback,
  366.             &forms[(int)form_type]);
  367.  
  368.     return shell;
  369. }
  370.  
  371.  
  372. /*
  373.  * Read-only popups.
  374.  */
  375. struct rop {
  376.     const char *name;            /* resource name */
  377.     XtGrabKind grab;            /* grab kind */
  378.     Boolean is_error;            /* is it? */
  379.     const char *itext;            /* initial text */
  380.     Widget shell;                /* pop-up shell */
  381.     Widget form;                /* dialog form */
  382.     Widget cancel_button;            /* cancel button */
  383.     abort_callback_t *cancel_callback;    /* callback for cancel button */
  384.     Boolean visible;            /* visibility flag */
  385. };
  386.  
  387. static struct rop error_popup = {
  388.     "errorPopup", XtGrabExclusive, True,
  389.     "first line\nsecond line",
  390.     NULL, NULL, NULL, NULL,
  391.     False
  392. };
  393. static struct rop info_popup = {
  394.     "infoPopup", XtGrabNonexclusive, False,
  395.     "first line\nsecond line",
  396.     NULL, NULL, NULL, NULL,
  397.     False
  398. };
  399.  
  400. static struct rop printer_error_popup = {
  401.     "printerErrorPopup", XtGrabExclusive, True,
  402.     "first line\nsecond line\nthird line\nfourth line",
  403.     NULL, NULL, NULL, NULL, False
  404. };
  405. static struct rop printer_info_popup = {
  406.     "printerInfoPopup", XtGrabNonexclusive, False,
  407.     "first line\nsecond line\nthird line\nfourth line",
  408.     NULL,
  409.     NULL, NULL, NULL, False
  410. };
  411.  
  412. /* Called when OK is pressed in a read-only popup */
  413. static void
  414. rop_ok(Widget w unused, XtPointer client_data, XtPointer call_data unused)
  415. {
  416.     struct rop *rop = (struct rop *)client_data;
  417.  
  418.     XtPopdown(rop->shell);
  419. }
  420.  
  421. /* Called when Cancel is pressed in a read-only popup */
  422. static void
  423. rop_cancel(Widget w unused, XtPointer client_data, XtPointer call_data unused)
  424. {
  425.     struct rop *rop = (struct rop *)client_data;
  426.  
  427.     XtPopdown(rop->shell);
  428.     if (rop->cancel_callback != NULL)
  429.         (*rop->cancel_callback)();
  430. }
  431.  
  432. /* Called when a read-only popup is closed */
  433. static void
  434. rop_popdown(Widget w unused, XtPointer client_data, XtPointer call_data unused)
  435. {
  436.     struct rop *rop = (struct rop *)client_data;
  437.  
  438.     rop->visible = False;
  439.     if (exiting && rop->is_error)
  440.         x3270_exit(1);
  441. }
  442.  
  443. /* Initialize a read-only pop-up. */
  444. static void
  445. rop_init(struct rop *rop)
  446. {
  447.     Widget w;
  448.  
  449.     if (rop->shell != NULL)
  450.         return;
  451.  
  452.     rop->shell = XtVaCreatePopupShell(
  453.         rop->name, transientShellWidgetClass, toplevel,
  454.         NULL);
  455.     XtAddCallback(rop->shell, XtNpopupCallback, place_popup,
  456.         (XtPointer) CenterP);
  457.     XtAddCallback(rop->shell, XtNpopdownCallback, rop_popdown, rop);
  458.  
  459.     /* Create a dialog in the popup */
  460.     rop->form = XtVaCreateManagedWidget(
  461.         ObjDialog, dialogWidgetClass, rop->shell,
  462.         NULL);
  463.     XtVaSetValues(XtNameToWidget(rop->form, XtNlabel),
  464.         XtNlabel, rop->itext,
  465.         NULL);
  466.  
  467.     /* Add "OK" button to the dialog */
  468.     w = XtVaCreateManagedWidget(
  469.         ObjConfirmButton, commandWidgetClass, rop->form,
  470.         NULL);
  471.     XtAddCallback(w, XtNcallback, rop_ok, rop);
  472.  
  473.     /* Add an unmapped "Cancel" button to the dialog */
  474.     rop->cancel_button = XtVaCreateManagedWidget(
  475.         ObjCancelButton, commandWidgetClass, rop->form,
  476.         XtNright, w,
  477.         XtNmappedWhenManaged, False,
  478.         NULL);
  479.     XtAddCallback(rop->cancel_button, XtNcallback, rop_cancel, rop);
  480.  
  481.     /* Force it into existence so it sizes itself with 4-line text */
  482.     XtRealizeWidget(rop->shell);
  483. }
  484.  
  485. /* Pop up a dialog.  Common logic for all forms. */
  486. static void
  487. popup_rop(struct rop *rop, abort_callback_t *a, const char *fmt, va_list args)
  488. {
  489.     (void) vsprintf(vmsgbuf, fmt, args);
  490.     if (!rop->shell) {
  491.         (void) fprintf(stderr, "%s: %s\n", programname, vmsgbuf);
  492.         exit(1);
  493.     }
  494.  
  495.     if (rop->is_error && sms_redirect()) {
  496.         sms_error(vmsgbuf);
  497.         return;
  498.     }
  499.  
  500.     XtVaSetValues(rop->form, XtNlabel, vmsgbuf, NULL);
  501.     if (a != NULL)
  502.         XtMapWidget(rop->cancel_button);
  503.     else
  504.         XtUnmapWidget(rop->cancel_button);
  505.     rop->cancel_callback = a;
  506.     if (!rop->visible) {
  507.         if (rop->is_error)
  508.             ring_bell();
  509.         rop->visible = True;
  510.         popup_popup(rop->shell, rop->grab);
  511.     }
  512. }
  513.  
  514. static void
  515. error_exit(void)
  516. {
  517.     x3270_exit(0);
  518. }
  519.  
  520. /* Pop up an error dialog. */
  521. void
  522. popup_an_error(const char *fmt, ...)
  523. {
  524.     va_list args;
  525.  
  526.     va_start(args, fmt);
  527.     popup_rop(&error_popup, appres.reconnect? error_exit: NULL, fmt, args);
  528.     va_end(args);
  529. }
  530.  
  531. /* Pop down an error dialog. */
  532. void
  533. popdown_an_error(void)
  534. {
  535.     if (error_popup.visible) {
  536.         XtPopdown(error_popup.shell);
  537.     }
  538. }
  539.  
  540. /* Pop up an error dialog, based on an error number. */
  541. void
  542. popup_an_errno(int errn, const char *fmt, ...)
  543. {
  544.     va_list args;
  545.     char *s;
  546.  
  547.     va_start(args, fmt);
  548.     (void) vsprintf(vmsgbuf, fmt, args);
  549.     va_end(args);
  550.     s = XtNewString(vmsgbuf);
  551.  
  552.     if (errn > 0)
  553.         popup_an_error("%s:\n%s", s, strerror(errn));
  554.     else
  555.         popup_an_error(s);
  556.     XtFree(s);
  557. }
  558.  
  559. /* Pop up an info dialog. */
  560. void
  561. popup_an_info(const char *fmt, ...)
  562. {
  563.     va_list args;
  564.  
  565.     va_start(args, fmt);
  566.     popup_rop(&info_popup, NULL, fmt, args);
  567.     va_end(args);
  568. }
  569.  
  570. /*
  571.  * Produce a result of some sort.  If there is a script running, return it
  572.  * as the value; otherwise, pop it up as an info.
  573.  */
  574. void
  575. action_output(const char *fmt, ...)
  576. {
  577.     va_list args;
  578.  
  579.     va_start(args, fmt);
  580.     if (sms_redirect()) {
  581.         char buf[4096];
  582.  
  583.         (void) vsprintf(buf, fmt, args);
  584.         sms_info("%s", buf);
  585.     } else
  586.         popup_rop(&info_popup, NULL, fmt, args);
  587.     va_end(args);
  588. }
  589.  
  590. /* Initialization. */
  591.  
  592. void
  593. error_popup_init(void)
  594. {
  595.     rop_init(&error_popup);
  596. }
  597.  
  598. void
  599. info_popup_init(void)
  600. {
  601.     rop_init(&info_popup);
  602. }
  603.  
  604. void
  605. printer_popup_init(void)
  606. {
  607.     if (printer_error_popup.shell != NULL)
  608.         return;
  609.     rop_init(&printer_error_popup);
  610.     rop_init(&printer_info_popup);
  611. }
  612.  
  613. /* Query. */
  614. Boolean
  615. error_popup_visible(void)
  616. {
  617.     return error_popup.visible;
  618. }
  619.  
  620. /*
  621.  * Printer pop-up.
  622.  * Allows both error and info popups, and a cancel button.
  623.  *   is_err    If True, this is an error pop-up.  If false, this is an info
  624.  *        pop-up.
  625.  *   a        If non-NULL, the Cancel button is enabled, and this is the
  626.  *        callback function for it.  If NULL, there will be no Cancel
  627.  *        button.
  628.  *   fmt...    printf()-like format and arguments.
  629.  */
  630. void
  631. popup_printer_output(Boolean is_err, abort_callback_t *a, const char *fmt, ...)
  632. {
  633.     va_list args;
  634.  
  635.     va_start(args, fmt);
  636.     popup_rop(is_err? &printer_error_popup: &printer_info_popup, a, fmt,
  637.         args);
  638.     va_end(args);
  639. }
  640.  
  641. /*
  642.  * Script actions
  643.  */
  644. void
  645. Info_action(Widget w unused, XEvent *event, String *params,
  646.     Cardinal *num_params)
  647. {
  648.     action_debug(Info_action, event, params, num_params);
  649.     if (check_usage(Info_action, *num_params, 1, 1) < 0)
  650.         return;
  651.     popup_an_info(params[0]);
  652. }
  653.